package com.aop;



import com.log.Log;
import com.utils.SysContent;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * LG
 */
//@Component
//@Aspect
public class QueryAspect {
	// 获取开始时间
	private long BEGIN_TIME;

	// 获取结束时间
	private long END_TIME;
	//使用log4j工具类
	public static Logger logger = Logger.getLogger(LogAspect.class);
	// 定义本次log实体
	private Log log = new Log();

	@Autowired
	private  HttpServletRequest request;



	@Pointcut("execution(* com.web.controller..*.*(..))")
	private void controllerAspect() {
	}

	/**
	 * 方法执行
	 *
	 * @parampjp
	 * @return
	 * @throwsThrowable
	 */
	@Around("controllerAspect()")
	@ResponseBody
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		// 日志实体对象
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		// 获取当前登陆用户信息
		// UserloginUser=SessionUtil.getLoginSession(request);
		// if(loginUser==null){
		// log.setLoginAccount("————");
		// }else{
		// log.setLoginAccount(loginUser.getUserAuth().getIdentity());
		// }

		// 拦截的实体类，就是当前正在执行的controller
		Object target = pjp.getTarget();
		// 拦截的方法名称。当前正在执行的方法
		String methodName = pjp.getSignature().getName();
		System.out.println(methodName + "kkkkkkkkkkkk");
		// 拦截的方法参数
		Object[] args = pjp.getArgs();

		// 拦截的放参数类型
		Signature sig = pjp.getSignature();
		MethodSignature msig = null;
		if (!(sig instanceof MethodSignature)) {
			throw new IllegalArgumentException("该注解只能用于方法");
		}
		msig = (MethodSignature) sig;
		Class[] parameterTypes = msig.getMethod().getParameterTypes();

		Object object = null;

		Method method = null;
		try {
			// 反射获得方法对象
			method = target.getClass().getMethod(methodName, parameterTypes);

		} catch (NoSuchMethodException e1) {
			// TODOAuto-generatedcatchblock
			// e1.printStackTrace();
		} catch (SecurityException e1) {
			// TODOAuto-generatedcatchblock
			e1.printStackTrace();
		}

		if (null != method) {
			// 判断是否包含自定义的注解，说明一下这里的SystemLog就是我自己自定义的注解
			if (method.isAnnotationPresent(SystemLog.class)) {
				SystemLog systemlog = method.getAnnotation(SystemLog.class);
				log.setModule(systemlog.module());
				log.setMethod(systemlog.methods());
				log.setLoginIp(getIp(request));
				log.setActionUrl(request.getRequestURI());

				try {
					System.out.println(method.getParameters()[0].getName() + "-----");
					System.out.println(getParamVal(pjp, 0) + "-----");
					System.out.println(Integer.parseInt(String.valueOf(getParamVal(pjp, 0))) <= -1);
					if (Integer.parseInt(String.valueOf(getParamVal(pjp, 0))) <= -1) {
						writeContent(pjp, "请不要非法操作", null);

						// return "error";

					} else {

						object = pjp.proceed();
					}

					log.setDescription("执行成功");
					log.setState((short) 1);
				} catch (Throwable e) {
					// TODOAuto-generatedcatchblock
					log.setDescription("执行失败");
					log.setState((short) -1);
				}
			} else {// 没有包含注解
				object = pjp.proceed();
				log.setDescription("此操作不包含注解");
				log.setState((short) 0);
			}
		} else {// 不需要拦截直接执行
			object = pjp.proceed();
			log.setDescription("不需要拦截直接执行");
			log.setState((short) 0);
		}
		return object;
	}

	/**
	 * 获取ip地址
	 *
	 * @paramrequest
	 * @return
	 */
	private String getIp(HttpServletRequest request) {
		if (request.getHeader("x-forwarded-for") == null) {
			return request.getRemoteAddr();
		}
		return request.getHeader("x-forwarded-for");
	}

	// 找出将aop对象指定参数值
	public Object getParamVal(ProceedingJoinPoint joinPoint, int pramaindex) throws Throwable {
		Object[] args = joinPoint.getArgs();
		String classType = joinPoint.getTarget().getClass().getName();
		Class<?> clazz = Class.forName(classType);
		String clazzName = clazz.getName();
		String methodName = joinPoint.getSignature().getName();// 获取方法名称
		// 获取参数名称和值
		Map<String, Object> nameAndArgs = this.getFieldsName(this.getClass(), clazzName, methodName, args);
		// nameAndArgs的两种类型，用实体类接收的类似这样：
		// reqParams=com.ynet.finmall.innermanage.event.SaveOrUpdateRoleReqParam@616b9c0e
		// 用Map<String,Object>接收的是这样：menuNo=56473283，遍历这个map区分两种不同，使用不同的取值方式。
		// 根据获取到的值所属的不同类型通过两种不同的方法获取参数
		boolean flag = false;
		if (nameAndArgs != null && nameAndArgs.size() > 0) {
			int i = 0;
			for (Map.Entry<String, Object> entry : nameAndArgs.entrySet()) {
				if (i == pramaindex) {
					return entry.getValue();
				}
			}
		}
		return null;

	}

	// 将aop对象参数 组装为map
	private Map<String, Object> getFieldsName(Class cls, String clazzName, String methodName, Object[] args)
			throws Exception {
		Map<String, Object> map = new HashMap<String, Object>();
		ClassPool pool = ClassPool.getDefault();
		ClassClassPath classPath = new ClassClassPath(cls);
		pool.insertClassPath(classPath);
		CtClass cc = pool.get(clazzName);
		CtMethod cm = cc.getDeclaredMethod(methodName);
		MethodInfo methodInfo = cm.getMethodInfo();
		CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
		LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
		if (attr == null) {
			// exception
		}
		int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
		for (int i = 0; i < cm.getParameterTypes().length; i++) {
			map.put(attr.variableName(i + pos), args[i]);// paramNames即参数名
		}
		return map;
	}

	void writeContent(ProceedingJoinPoint pjp, String msg, String url) {
		// HttpServletRequest request = ((ServletRequestAttributes)
		// RequestContextHolder.getRequestAttributes())
		// .getRequest();

		// HttpServletResponse response = ((ServletWebRequest)
		// RequestContextHolder.getRequestAttributes()).getResponse();

		//HttpServletRequest request = SysContent.getRequest();
		HttpServletResponse response = SysContent.getResponse();



		try {
			request.setAttribute("msg", msg);
			request.getRequestDispatcher("/error.jsp").forward(request, response);
		} catch (ServletException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


	}
}
